// XTPSkinObjectMDI.cpp: implementation of the CXTPSkinObjectMDI class.
//
// This file is a part of the XTREME SKINFRAMEWORK MFC class library.
// (c)1998-2009 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "Common/XTPDrawHelpers.h"
#include "Common/XTPWinThemeWrapper.h"
#include "Common/XTPSystemHelpers.h"

#include "XTPSkinObjectMenu.h"
#include "XTPSkinManager.h"
#include "XTPSkinDrawTools.h"

#define TIMERID_MENUSHOW 0xACC
#define TIMERID_MENUHIDE 0xABB

#ifndef WM_UNINITMENUPOPUP
#define WM_MENURBUTTONUP                0x0122
#define WM_MENUDRAG                     0x0123
#define WM_MENUGETOBJECT                0x0124
#define WM_UNINITMENUPOPUP              0x0125
#define WM_MENUCOMMAND                  0x0126
#endif

#ifndef SPI_GETMENUSHOWDELAY
#define SPI_GETMENUSHOWDELAY       0x006A
#endif

#define TPM_SYSMENU 0x0200L

#ifndef HBMMENU_CALLBACK
#define MIIM_STRING      0x00000040
#define MIIM_BITMAP      0x00000080
#define MIIM_FTYPE       0x00000100

#define HBMMENU_CALLBACK            ((HBITMAP) -1)
#define HBMMENU_SYSTEM              ((HBITMAP)  1)
#define HBMMENU_MBAR_RESTORE        ((HBITMAP)  2)
#define HBMMENU_MBAR_MINIMIZE       ((HBITMAP)  3)
#define HBMMENU_MBAR_CLOSE          ((HBITMAP)  5)
#define HBMMENU_MBAR_CLOSE_D        ((HBITMAP)  6)
#define HBMMENU_MBAR_MINIMIZE_D     ((HBITMAP)  7)
#define HBMMENU_POPUP_CLOSE         ((HBITMAP)  8)
#define HBMMENU_POPUP_RESTORE       ((HBITMAP)  9)
#define HBMMENU_POPUP_MAXIMIZE      ((HBITMAP) 10)
#define HBMMENU_POPUP_MINIMIZE      ((HBITMAP) 11)
#endif


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif




//////////////////////////////////////////////////////////////////////////
// CXTPSkinObjectApplicationFrame

IMPLEMENT_DYNCREATE(CXTPSkinObjectApplicationFrame, CXTPSkinObjectFrame)

CXTPSkinObjectApplicationFrame::CXTPSkinObjectApplicationFrame()
{
	m_rcMenuBar.SetRectEmpty();

	m_pPopupMenu = new CXTPSkinPopupMenu();
	m_pPopupMenu->m_bMenuBar = TRUE;
};



CXTPSkinObjectApplicationFrame::~CXTPSkinObjectApplicationFrame()
{
	if (m_pPopupMenu) m_pPopupMenu->InternalRelease();
};

BEGIN_MESSAGE_MAP(CXTPSkinObjectApplicationFrame, CXTPSkinObjectFrame)
	//{{AFX_MSG_MAP(CXTPSkinObjectMenu)
	ON_WM_NCCALCSIZE()
	ON_WM_CONTEXTMENU()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CXTPSkinObjectApplicationFrame::FrameHasMenuBar()
{
	if (GetStyle() & WS_CHILD)
		return FALSE;

	HMENU hMenu = ::GetMenu(m_hWnd);
	if (!hMenu)
		return FALSE;

	return GetMenuItemCount(hMenu) > 0;
}

void CXTPSkinObjectApplicationFrame::DrawFrame(CDC* pDC)
{
	if (m_bLockFrameDraw)
		return;

	if (!m_rcMenuBar.IsRectEmpty())
	{
		DrawFrameMenuBar(pDC);
	}

	CXTPSkinObjectFrame::DrawFrame(pDC);
}

void CXTPSkinObjectApplicationFrame::UpdateMenuBar()
{
	if (FrameHasMenuBar())
	{
		RebuildMenuItems();
	}
	else
	{
		if (m_pPopupMenu) m_pPopupMenu->m_hMenu = NULL;
		m_rcMenuBar.SetRectEmpty();
	}
}

void CXTPSkinObjectApplicationFrame::RedrawMenuBar()
{
	if (!m_rcMenuBar.IsRectEmpty())
	{
		CWindowDC dc(this);
		DrawFrameMenuBar(&dc);

		CXTPClientRect rect(this);
		if (rect.Height() <= 0)
			CXTPSkinObjectFrame::DrawFrame(&dc);
	}
}


void CXTPSkinObjectApplicationFrame::DrawFrameMenuBar(CDC* pDC)
{
	CXTPSkinManager* pSkinManager = XTPSkinManager();
	CXTPSkinManagerClass* pClassWindow = pSkinManager->GetSkinClass(this, _T("WINDOW"));

	CRect rc = m_rcMenuBar;
	CXTPBufferDC dc(*pDC, rc);

	dc.FillSolidRect(rc.left, rc.top, rc.Width(), rc.Height() - 1, GetColor(COLOR_3DFACE));
	dc.FillSolidRect(rc.left, rc.bottom - 1, rc.Width(), 1, GetColor(COLOR_WINDOW));

	CXTPFontDC font(&dc, &GetMetrics()->m_fntMenu);
	dc.SetBkMode(TRANSPARENT);

	int nCount = m_pPopupMenu->GetCount();


	for (int nIndex = 0; nIndex < nCount; nIndex++ )
	{
		CXTPSkinPopupMenuItem* pItem = m_pPopupMenu->GetItem(nIndex);
		CRect rcItem = pItem->m_rcItem;
		BOOL bSelected = nIndex == m_pPopupMenu->m_nSelected;
		BOOL bEnabled = pItem->IsEnabled();

		HBITMAP hbm = pItem->GetItemBitmap();

		if (hbm == HBMMENU_SYSTEM)
		{
			HWND hwndItem = (HWND)pItem->GetItemData();
			if (hwndItem && IsWindow(hwndItem))
			{
				HICON hIcon = GetSchema()->GetFrameSmIcon(hwndItem, FALSE);

				if (hIcon)
				{
					rcItem = CRect(CPoint(rcItem.CenterPoint().x - 8, rcItem.CenterPoint().y - 8), CSize(16, 16));

					DrawIconEx(dc.m_hDC, rcItem.left, rcItem.top, hIcon,
						rcItem.Width(), rcItem.Height(), 0, NULL, DI_NORMAL);
				}
			}

			continue;
		}

		if (pItem->IsSeparator())
			continue;

		if (pItem->IsMDISysButton())
		{
			UINT nID = pItem->GetID();
			int nPartID = nID == SC_RESTORE ? WP_MDIRESTOREBUTTON : nID == SC_MINIMIZE ? WP_MDIMINBUTTON : WP_MDICLOSEBUTTON;
			int nState = !bEnabled ? SBS_DISABLED : bSelected ?  SBS_HOT : SBS_NORMAL;

			pClassWindow->DrawThemeBackground(&dc, nPartID, nState, &rcItem);

			continue;
		}

		CString strMenuText = m_pPopupMenu->GetMenuString(nIndex);

		if (bSelected)
		{
			dc.FillSolidRect(rcItem, GetColor(COLOR_HIGHLIGHT));
		}

		dc.SetTextColor(GetColor(!bEnabled ? COLOR_GRAYTEXT : bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));

		dc.DrawText(strMenuText, rcItem, DT_VCENTER | DT_CENTER | DT_SINGLELINE);
	}
}

void CXTPSkinObjectApplicationFrame::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS FAR* lpncsp)
{
	CXTPSkinObjectFrame::OnNcCalcSize(bCalcValidRects, lpncsp);

	if (FrameHasMenuBar())
	{
		m_rcMenuBar.SetRect(m_rcBorders.left, m_rcBorders.top, m_rcBorders.left + lpncsp[0].rgrc->right - lpncsp[0].rgrc->left, m_rcBorders.top);

		RebuildMenuItems();

		lpncsp[0].rgrc->top += m_rcMenuBar.Height();
	}
	else
	{
		if (m_pPopupMenu) m_pPopupMenu->m_hMenu = NULL;
		m_rcMenuBar.SetRectEmpty();
	}
}

BOOL CXTPSkinPopupMenuItem::IsMDISysButton() const
{
	int nID = GetID();
	if (nID == SC_CLOSE || nID == SC_RESTORE || nID == SC_MINIMIZE)
		return TRUE;

	return FALSE;
}

void CXTPSkinObjectApplicationFrame::RebuildMenuItems()
{
	m_pPopupMenu->RemoveAll();
	m_pPopupMenu->m_hMenu = NULL;

	if (GetStyle() & WS_CHILD)
		return;

	HMENU hMenu = ::GetMenu(m_hWnd);
	if (!hMenu)
		return;

	m_pPopupMenu->m_hMenu = hMenu;
	m_pPopupMenu->m_hWnd = m_hWnd;
	m_pPopupMenu->m_hWndNotify = m_hWnd;

	int nCount = ::GetMenuItemCount(hMenu);

	CWindowDC dc(this);

	CXTPFontDC font(&dc, &GetMetrics()->m_fntMenu);

	int nHeight = GetSystemMetrics(SM_CYMENUSIZE);

	//CRect rc = m_rcMenuBar;

	int x = m_rcMenuBar.left;
	int y = m_rcMenuBar.top;

	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);

	int nIndex;

	for (nIndex = 0; nIndex < nCount; nIndex++ )
	{
		CXTPSkinPopupMenuItem* pItem = new CXTPSkinPopupMenuItem(m_pPopupMenu, nIndex);

		CSize sz(0, 0);

		HBITMAP hbm = pItem->GetItemBitmap();
		if ((UINT_PTR)hbm == 1)
		{
			sz.cx = 16 + 2 + 2;
			sz.cy = 16;
		}
		else if (pItem->IsSeparator())
			sz.cx = 6;
		else if (pItem->IsMDISysButton())
		{
			sz.cx = sz.cy = nHeight;
		}
		else
		{
			CString strMenuText = pItem->GetText();
			XTPDrawHelpers()->StripMnemonics(strMenuText);

			int nText = dc.GetTextExtent(strMenuText).cx;
			sz.cx = nText + (tm.tmAveCharWidth + 1) * 2;
			sz.cy = nHeight;
		}

		if (x + sz.cx > m_rcMenuBar.right && nIndex != 0)
		{
			y += nHeight;
			x = m_rcMenuBar.left;
		}

		CRect rcItem(x, y, x + sz.cx, y + nHeight);

		pItem->m_rcItem = rcItem;

		m_pPopupMenu->m_arrItems.Add(pItem);

		x = rcItem.right;
	}

	x = m_rcMenuBar.right;

	for (nIndex = nCount - 1; nIndex >= 0; nIndex--)
	{
		CXTPSkinPopupMenuItem* pItem = m_pPopupMenu->GetItem(nIndex);

		if ((pItem->GetType() & MFT_RIGHTJUSTIFY || pItem->IsMDISysButton()) && pItem->m_rcItem.top == y)
		{
			pItem->m_rcItem.OffsetRect(x - pItem->m_rcItem.right, 0);
			x -= pItem->m_rcItem.Width();
		}
		else
		{
			break;
		}
	}

	m_rcMenuBar.bottom = y + nHeight + 1;
}

int CXTPSkinObjectApplicationFrame::HitTestMenuItem(CPoint point)
{
	if (!m_rcMenuBar.PtInRect(point))
		return -1;

	for (int i = 0; i < m_pPopupMenu->GetCount(); i++)
	{
		if (::PtInRect(&m_pPopupMenu->GetItem(i)->m_rcItem, point))
			return i;
	}

	return -1;
}

BOOL CXTPSkinObjectApplicationFrame::HandleMouseMove(CPoint point)
{
	if (CXTPSkinObjectFrame::HandleMouseMove(point))
		return TRUE;

	if (m_rcMenuBar.IsRectEmpty())
		return FALSE;

	CPoint ptClient(point);
	ScreenToFrame(&ptClient);

	int nSelected = HitTestMenuItem(ptClient);

	if (nSelected != -1 && HandleNcHitTest(point) != HTMENU)
		nSelected = -1;

	if (m_pPopupMenu->m_nSelected != nSelected)
	{
		m_pPopupMenu->m_nSelected = nSelected;
		RedrawMenuBar();

		if (nSelected != -1)
			SetTimer (XTP_TID_MOUSELEAVE, 50, &CXTPSkinObjectFrame::OnTimerInternal);
		else
			CancelMouseLeaveTracking();

	}
	return TRUE;
}

LRESULT CXTPSkinObjectApplicationFrame::HandleNcHitTest(CPoint point)
{
	if (!m_rcMenuBar.IsRectEmpty())
	{
		CPoint ptMenu(point);
		ScreenToFrame(&ptMenu);

		CRect rcMenuBar(m_rcMenuBar);

		CXTPWindowRect rcWindow(this);
		rcWindow.OffsetRect(-rcWindow.TopLeft());
		rcWindow.DeflateRect(m_rcBorders);

		rcMenuBar.IntersectRect(rcMenuBar, rcWindow);
		rcMenuBar.top += 1;

		if (rcMenuBar.PtInRect(ptMenu))
			return HTMENU;
	}

	return CXTPSkinObjectFrame::HandleNcHitTest(point);
}

CXTPSkinPopupMenuState* CXTPSkinObjectApplicationFrame::StartMenuState(UINT /*nID*/, LPARAM /*lParam*/)
{
	if (m_pPopupMenu->m_hMenu == 0)
	{
		HMENU hMenu = ::GetSystemMenu(m_hWnd, FALSE);
		if (!hMenu)
			return NULL;

		::SetMenuDefaultItem(hMenu, SC_CLOSE, MF_BYCOMMAND);

		m_pPopupMenu->m_hMenu = hMenu;
		m_pPopupMenu->m_bSysMenu = TRUE;
		m_pPopupMenu->m_hWnd = m_hWnd;
		m_pPopupMenu->m_hWndNotify = m_hWnd;

		m_pPopupMenu->PositionSysMenu();
	}

	CXTPSkinPopupMenuState* pState = new CXTPSkinPopupMenuState(m_hWnd);
	pState->InitMenu(m_pPopupMenu);

	return pState;
}

void CXTPSkinPopupMenuState::PlayEventSound(UINT nID)
{
	XTPSoundManager()->PlaySystemSound((XTPSoundManagerState)nID);
}

void CXTPSkinPopupMenuState::EndState()
{
	if (m_pAlternatePopup)
	{
		if (!m_pAlternatePopup->IsSysMenuBar())
		{
			CXTPSkinPopupMenu* pAlternatePopup = m_pAlternatePopup;
			m_pAlternatePopup = m_pRootPopup;
			m_pRootPopup = pAlternatePopup;
		}

		m_pAlternatePopup->InternalRelease();
	}
	else if (m_pRootPopup && m_pRootPopup->m_bSysMenu)
	{
		m_pRootPopup->m_bSysMenu = FALSE;
		m_pRootPopup->m_hMenu = NULL;
		m_pRootPopup->m_hWnd = NULL;
	}

	if (m_pRootPopup)
	{
		m_pRootPopup->InternalRelease();
	}

	delete this;
}

void CXTPSkinPopupMenuState::FilterMenuKey(LPARAM lParam)
{


	if (m_bButtonDown)
		return;

	if (!StartMenu(focusKeyboard))
		return;

	m_bInsideMenuLoop = TRUE;

	switch (lParam)
	{
		case 0:
			SelectItem(m_pRootPopup, 0);
			RunLoop(lParam);
			return;

		case '-':
			if ((GetWindowLong(m_pRootPopup->m_hWndNotify, GWL_STYLE) & WS_CHILD) == 0)
			{
				break;
			}
			// else fall through.

		case ' ':
			if (!m_pAlternatePopup && !m_pRootPopup->m_bSysMenu)
			{
				Dismiss();
				return;
			}

			CloseHierarchy(m_pRootPopup);

			if (!m_pRootPopup->m_bSysMenu)
				SwitchToAlternateMenu();

			SelectItem(m_pRootPopup, 0);
			OpenHierarchy(m_pRootPopup);
			m_pRootPopup->m_bToggle = FALSE;
			RunLoop(lParam);
			return;

	}

	OnChar(m_pRootPopup, (UINT)lParam);
	if (m_pRootPopup->m_nSelected != -1)
	{
		RunLoop(lParam);
	}
	else
	{
		Dismiss();
	}
}

BOOL CXTPSkinObjectApplicationFrame::HandleSysCommand(UINT nID, LPARAM lParam)
{
	if ((GetSkinManager()->GetApplyOptions() & xtpSkinApplyMenus) == 0)
		return CXTPSkinObjectFrame::HandleSysCommand(nID, lParam);

	UINT nCmd = (nID & 0xFFF0);

	if (nCmd == SC_DEFAULT)
	{
		return TRUE;
	}
	if (nCmd == SC_MOUSEMENU)
	{
		CXTPSkinPopupMenuState* pState = StartMenuState(nID, lParam);
		if (pState)
		{
			pState->RunLoop(lParam);

			pState->EndState();
		}
		return TRUE;
	}

	if (nCmd == SC_KEYMENU)
	{
		CXTPSkinPopupMenuState* pState = StartMenuState(nID, lParam);
		if (pState)
		{
			pState->FilterMenuKey(lParam);

			pState->EndState();
		}
		else
		{
			CXTPSkinObjectFrame::HandleSysCommand(nID, lParam);
		}
		return TRUE;
	}

	return FALSE;
}



//////////////////////////////////////////////////////////////////////////
// CXTPSkinPopupMenuItem

CXTPSkinPopupMenuItem::CXTPSkinPopupMenuItem(CXTPSkinPopupMenu* pPopupMenu, int nItem)
{
	m_hMenu = pPopupMenu->m_hMenu;
	m_nItem = nItem;
	m_pPopupMenu = pPopupMenu;

	m_rcItem.SetRectEmpty();
}

CRect CXTPSkinPopupMenuItem::GetScreenPos() const
{
	CRect rcItem(m_rcItem);

	CXTPSkinPopupMenuState::WindowToScreen(m_pPopupMenu->m_hWnd, rcItem);

	return rcItem;
}

HMENU CXTPSkinPopupMenuItem::GetPopupMenu() const
{
	if (m_pPopupMenu->IsSysMenuBar())
		return m_hMenu;

	return ::GetSubMenu(m_hMenu, m_nItem);
}

DWORD CXTPSkinPopupMenuItem::GetState() const
{
	if (m_pPopupMenu->IsSysMenuBar())
		return MF_ENABLED;

	MENUITEMINFO mii;
	GetMenuItemInfo(MIIM_STATE, &mii);

	return mii.fState;
}

void CXTPSkinPopupMenuItem::GetMenuItemInfo(UINT fMask, LPMENUITEMINFO lpMII) const
{
	ZeroMemory(lpMII, sizeof(MENUITEMINFO));
	lpMII->cbSize = sizeof(MENUITEMINFO);
	lpMII->fMask = fMask;

	::GetMenuItemInfo(m_hMenu, m_nItem, TRUE, lpMII);
}

UINT CXTPSkinPopupMenuItem::GetID() const
{
	MENUITEMINFO mii;
	GetMenuItemInfo(MIIM_ID, &mii);

	return mii.wID;
}

BOOL CXTPSkinPopupMenuItem::IsEnabled() const
{
	return (GetState() & MFS_GRAYED) == 0;
}

BOOL CXTPSkinPopupMenuItem::IsChecked() const
{
	return (GetState() & MFS_CHECKED);
}

BOOL CXTPSkinPopupMenuItem::IsDefault() const
{
	return (GetState() & MFS_DEFAULT);
}


DWORD_PTR CXTPSkinPopupMenuItem::GetItemData() const
{
	MENUITEMINFO mii;
	GetMenuItemInfo(MIIM_DATA, &mii);

	return mii.dwItemData;
}

CString CXTPSkinPopupMenuItem::GetText() const
{
	CString strText;
	::GetMenuString(m_hMenu, m_nItem, strText.GetBuffer(256), 256, MF_BYPOSITION);
	strText.ReleaseBuffer();
	return strText;
}

BOOL CXTPSkinPopupMenuItem::IsSeparator() const
{
	MENUITEMINFO mii;
	GetMenuItemInfo(MIIM_TYPE, &mii);

	return mii.fType & MFT_SEPARATOR;
}

BOOL CXTPSkinPopupMenuItem::IsOwnerDraw() const
{
	MENUITEMINFO mii;
	GetMenuItemInfo(MIIM_TYPE, &mii);

	return mii.fType & MFT_OWNERDRAW;
}

UINT CXTPSkinPopupMenuItem::GetType() const
{
	MENUITEMINFO mii;
	GetMenuItemInfo(MIIM_TYPE, &mii);

	return mii.fType;
}

#ifndef MIIM_BITMAP
#define MIIM_BITMAP      0x00000080
#endif

HBITMAP CXTPSkinPopupMenuItem::GetItemBitmap() const
{
	struct MENUITEMINFO98
	{
		UINT    cbSize;
		UINT    fMask;
		UINT    fType;          // used if MIIM_TYPE (4.0) or MIIM_FTYPE (>4.0)
		UINT    fState;         // used if MIIM_STATE
		UINT    wID;            // used if MIIM_ID
		HMENU   hSubMenu;       // used if MIIM_SUBMENU
		HBITMAP hbmpChecked;    // used if MIIM_CHECKMARKS
		HBITMAP hbmpUnchecked;  // used if MIIM_CHECKMARKS
		DWORD   dwItemData;     // used if MIIM_DATA
		LPWSTR  dwTypeData;     // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0)
		UINT    cch;            // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0)
		HBITMAP hbmpItem;       // used if MIIM_BITMAP
	};

	if (XTPSystemVersion()->IsWin95() || XTPSystemVersion()->IsWinNT4())
		return NULL;

	MENUITEMINFO98 mii;
	ZeroMemory(&mii, sizeof(MENUITEMINFO98));
	mii.cbSize = sizeof(MENUITEMINFO98);
	mii.fMask = MIIM_BITMAP;

	::GetMenuItemInfo(m_hMenu, m_nItem, TRUE, (MENUITEMINFO*)&mii);

	return mii.hbmpItem;
}



//////////////////////////////////////////////////////////////////////////
// CXTPSkinPopupMenu

CXTPSkinPopupMenu::CXTPSkinPopupMenu()
{
	m_bMenuBar = FALSE;
	m_bSendUninit = FALSE;
	m_bSysMenu = FALSE;
	m_hWnd = 0;
	m_nSelected = -1;
	m_nDropped = -1;
	m_hMenu = NULL;
	m_pNextPopup = NULL;
	m_pPrevPopup = NULL;
	m_bToggle = FALSE;
	m_bDropNextPopup = FALSE;
	m_hWndNotify = 0;
	m_bAboutToHide = FALSE;
	m_bDroppedLeft = FALSE;

	m_pState = NULL;

	m_nHideTimer = 0;
	m_nShowTimer = 0;
}

CXTPSkinPopupMenu::~CXTPSkinPopupMenu()
{
	m_hWnd = NULL;
	RemoveAll();
}

void CXTPSkinPopupMenu::OnFinalRelease()
{
	delete this;
}

void CXTPSkinPopupMenu::RemoveAll()
{
	for (int i = 0; i < m_arrItems.GetSize(); i++)
	{
		delete m_arrItems[i];
	}
	m_arrItems.RemoveAll();
}

CString CXTPSkinPopupMenu::GetMenuString(int nIndex)
{
	CString strMenuText;

	if (m_hMenu)
	{
		::GetMenuString(m_hMenu, nIndex, strMenuText.GetBuffer(256), 256, MF_BYPOSITION);
		strMenuText.ReleaseBuffer();
	}
	return strMenuText;
}

void CXTPSkinPopupMenu::RebuildItems()
{
	RemoveAll();

	int nCount = !IsSysMenuBar() ? GetMenuItemCount(m_hMenu) : 1;

	for (int i = 0; i < nCount; i++)
	{
		m_arrItems.Add(new CXTPSkinPopupMenuItem(this, i));
	}
}

int CXTPSkinPopupMenu::GetCount()
{
	int nCount = !IsSysMenuBar() ? GetMenuItemCount(m_hMenu) : 1;
	if (nCount != m_arrItems.GetSize())
	{
		RebuildItems();
	}

	return nCount;
}

CXTPSkinPopupMenuItem* CXTPSkinPopupMenu::GetItem(int nIndex) const
{
	return nIndex >= 0 && nIndex < m_arrItems.GetSize() ? m_arrItems.GetAt(nIndex) : NULL;
}

BEGIN_MESSAGE_MAP(CXTPSkinPopupMenu, CWnd)
	//{{AFX_MSG_MAP(CXTPSkinObjectMenu)
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL CXTPSkinPopupMenu::IsMenuThemed()
{
	CXTPSkinManager* pSkinManager = XTPSkinManager();
	CXTPSkinManagerClass* pClass = pSkinManager->GetSkinClass(pSkinManager->Lookup(m_hWndNotify), _T("MENU"));

	BOOL bTheme = pClass->GetThemeInt(XTP_MP_POPUPBACKGROUND, 0, TMT_BORDERSIZE, 0) != 0;
	if (!bTheme)
		return FALSE;

	int nCount = ::GetMenuItemCount(m_hMenu);

	for (int i = 0; i < nCount; i++)
	{
		MENUITEMINFO mii;
		ZeroMemory(&mii, sizeof(MENUITEMINFO));
		mii.cbSize = sizeof(MENUITEMINFO);
		mii.fMask = MIIM_TYPE;
		::GetMenuItemInfo(m_hMenu, i, TRUE, &mii);

		if (mii.fType & MFT_OWNERDRAW)
			return FALSE;
	}

	return TRUE;

}

void CXTPSkinPopupMenu::PositionSysMenu()
{
	RebuildItems();

	ASSERT(GetCount() == 1);

	CXTPSkinPopupMenuItem* pItem = GetItem(0);

	HWND hWnd = m_hWndNotify;
	DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
	DWORD dwExStyle = GetWindowLong(hWnd, GWL_EXSTYLE);

	CRect rcBorders = XTPSkinManager()->GetSchema()->CalcFrameBorders(dwStyle, dwExStyle);

	pItem->m_rcItem.SetRect(rcBorders.left, rcBorders.left, rcBorders.top, rcBorders.top);
}

CSize CXTPSkinPopupMenu::RecalcLayout()
{
	ASSERT(m_pState);
	ASSERT(!m_bMenuBar);

	CXTPSkinManagerMetrics* pMetrics = m_pState->m_pSchema->GetMetrics();

	BOOL bTheme = IsMenuThemed();

	CDC dc;
	dc.Attach(::GetWindowDC(m_hWnd));

	CXTPFontDC font(&dc, &pMetrics->m_fntMenu);

	CRect rcBorders(3, 3, 3, 3);

	int x = rcBorders.left;
	int y = rcBorders.top;

	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);

	RemoveAll();

	int nCount = ::GetMenuItemCount(m_hMenu), nItem;

	int nMaxWidthColumn = 0;
	int nFirstColumn = 0;
	int nMaxHeight = 0;

	for (nItem = 0; nItem < nCount; nItem++ )
	{
		CXTPSkinPopupMenuItem* pItem = new CXTPSkinPopupMenuItem(this, nItem);

		CString strMenuText = pItem->GetText();

		CSize szText(0, 0);

		if (pItem->IsOwnerDraw())
		{
			MEASUREITEMSTRUCT mis;
			mis.CtlType = ODT_MENU;
			mis.CtlID = 0;
			mis.itemID  = pItem->GetID();
			mis.itemWidth = 0;
			mis.itemHeight= (UINT) dc.GetTextExtent(_T(" "), 1).cy;
			mis.itemData = pItem->GetItemData();

			::SendMessage(m_hWndNotify, WM_MEASUREITEM, 0, (LPARAM)&mis);

			szText.cx = mis.itemWidth + 12;
			szText.cy = mis.itemHeight;

		}
		else if (pItem->IsSeparator())
		{
			szText.cy = bTheme ? 6 : 9;
		}
		else
		{
			BOOL bDefault = pItem->IsDefault();
			CFont fontDefault;

			if (bDefault)
			{
				LOGFONT lf;
				pMetrics->m_fntMenu.GetLogFont(&lf);
				lf.lfWeight  = FW_BOLD;
				fontDefault.CreateFontIndirect(&lf);
				font.SetFont(&fontDefault);
			}

			int nIndex = strMenuText.Find(_T('\t'));

			CSize szShortcut(0, 0);

			if (nIndex != -1)
			{
				CString strShortcutText = strMenuText.Mid(nIndex);
				strMenuText.ReleaseBuffer(nIndex);

				szShortcut = dc.GetTextExtent(strShortcutText);
			}

			szText = dc.GetTextExtent(strMenuText);

			if (bTheme)
			{
				szText.cx = 33 + szText.cx + szShortcut.cx + 55;
				szText.cy = max(szText.cy, 22);
			}
			else
			{
				szText.cx = 17 + szText.cx + szShortcut.cx + 44;
				szText.cy = max(szText.cy, 17);
			}

			if (bDefault)
			{
				font.SetFont(&pMetrics->m_fntMenu);
			}
		}

		if ((pItem->GetType() & (MF_MENUBREAK | MF_MENUBARBREAK)) && (nItem != nFirstColumn))
		{
			for (; nFirstColumn < nItem; nFirstColumn++ )
			{
				CXTPSkinPopupMenuItem* pItem = m_arrItems[nFirstColumn];
				pItem->m_rcItem.right = pItem->m_rcItem.left + nMaxWidthColumn;
			}

			x += nMaxWidthColumn + 4;
			nMaxHeight = max(nMaxHeight, y);
			y = rcBorders.top;
			nMaxWidthColumn = 0;
		}

		CRect rcItem(x, y, x + szText.cx, y + szText.cy);
		nMaxWidthColumn = max(nMaxWidthColumn, szText.cx);

		pItem->m_rcItem = rcItem;

		m_arrItems.Add(pItem);

		y = rcItem.bottom;
	}

	for (nItem = nFirstColumn; nItem < nCount; nItem++ )
	{
		CXTPSkinPopupMenuItem* pItem = m_arrItems[nItem];
		pItem->m_rcItem.right = pItem->m_rcItem.left + nMaxWidthColumn;
	}

	int nTotalWidth = x + nMaxWidthColumn + rcBorders.right;
	nMaxHeight = max(nMaxHeight, y)  + rcBorders.bottom;

	font.ReleaseFont();

	::ReleaseDC(m_hWnd, dc.Detach());
	return CSize(nTotalWidth, nMaxHeight);
}

void CXTPSkinPopupMenu::OnPaint()
{

	CPaintDC dcPaint(this);
	CXTPBufferDC dc(dcPaint);

	if (!m_pState)
		return;

	CXTPSkinManager* pSkinManager = XTPSkinManager();
	CXTPSkinManagerMetrics* pMetrics = m_pState->m_pSchema->GetMetrics();

	CXTPClientRect rc(this);

	CXTPSkinManagerClass* pClass = pSkinManager->GetSkinClass(pSkinManager->Lookup(m_hWndNotify), _T("MENU"));

	BOOL bTheme = IsMenuThemed();;

	if (bTheme)
	{
		CRect rcBackground(rc);
		pClass->DrawThemeBackground(&dc, XTP_MP_POPUPBORDERS, 0, &rcBackground);
		rcBackground.DeflateRect(3, 3);
		pClass->DrawThemeBackground(&dc, XTP_MP_POPUPBACKGROUND, 0, &rcBackground);

		rcBackground.right = rcBackground.left + 28;
		pClass->DrawThemeBackground(&dc, XTP_MP_POPUPGUTTER, 0, &rcBackground);

	}
	else
	{
		dc.FillSolidRect(rc, pMetrics->GetColor(COLOR_MENU));
		dc.Draw3dRect(rc, pMetrics->GetColor(COLOR_3DSHADOW), pMetrics->GetColor(COLOR_3DSHADOW));
	}

	CXTPFontDC font(&dc, &pMetrics->m_fntMenu);
	dc.SetBkMode(TRANSPARENT);

	int nCount = GetCount();

	for (int nIndex = 0; nIndex < nCount; nIndex++)
	{
		CXTPSkinPopupMenuItem* pItem = GetItem(nIndex);

		MENUITEMINFO mii;
		ZeroMemory(&mii, sizeof(mii));
		mii.cbSize = sizeof(mii);
		mii.fMask = MIIM_STATE | MIIM_CHECKMARKS | MIIM_ID;

		::GetMenuItemInfo(m_hMenu, nIndex, TRUE, &mii);

		BOOL bSeparator = pItem->IsSeparator();
		BOOL bEnabled = pItem->IsEnabled();
		BOOL bSelected = (nIndex == m_nSelected) && !bSeparator;


		CRect rcItem(pItem->m_rcItem);

		if ((pItem->GetType() & MF_MENUBARBREAK) && (nIndex != 0) && !bTheme)
		{
			dc.FillSolidRect(rcItem.left - 3, rc.top + 3, 1, rc.Height() - 6, pMetrics->GetColor(COLOR_3DSHADOW));
			dc.FillSolidRect(rcItem.left - 2, rc.top + 3, 1, rc.Height() - 6, pMetrics->GetColor(COLOR_3DHIGHLIGHT));
		}

		if (pItem->IsOwnerDraw())
		{
			dc.SetTextColor(pMetrics->GetColor(COLOR_MENUTEXT));
			dc.SetBkColor(pMetrics->GetColor(COLOR_MENU));

			DWORD dwState = mii.fState;

			DRAWITEMSTRUCT dis;
			dis.CtlType = ODT_MENU;
			dis.CtlID = 0;
			dis.itemID = mii.wID;
			dis.itemAction = ODA_DRAWENTIRE;
			dis.itemState   =
				((dwState & MF_GRAYED)       ? ODS_GRAYED    : 0) |
				((dwState & MFS_DEFAULT)     ? ODS_DEFAULT   : 0) |
				((dwState & MFS_CHECKED)     ? ODS_CHECKED   : 0) |
				((dwState & MFS_DISABLED)    ? ODS_DISABLED  : 0) |
				(bSelected                   ? ODS_SELECTED  : 0);

			dis.hwndItem = (HWND)m_hMenu;
			dis.hDC = dc.GetSafeHdc();


			dis.rcItem = pItem->m_rcItem;
			dis.itemData = pItem->GetItemData();

			if (m_hWndNotify)
			{
				::SendMessage(m_hWndNotify, WM_DRAWITEM, 0, (LPARAM)&dis);
			}

			if (pItem->GetPopupMenu())
			{
				CPoint ptCenter(rcItem.right - (bTheme ? 10 : 5), rcItem.CenterPoint().y);
				XTPDrawHelpers()->Triangle(&dc, ptCenter, CPoint(ptCenter.x - 3, ptCenter.y - 3),
					CPoint(ptCenter.x - 3, ptCenter.y + 3), pMetrics->GetColor(!bEnabled ? COLOR_GRAYTEXT : bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));
			}
			continue;
		}
		if (bSeparator)
		{
			if (!bTheme)
			{
				dc.FillSolidRect(rcItem.left + 1, rcItem.CenterPoint().y, rcItem.Width() - 2, 1, pMetrics->GetColor(COLOR_3DSHADOW));
				dc.FillSolidRect(rcItem.left + 1, rcItem.CenterPoint().y + 1, rcItem.Width() - 2, 1, pMetrics->GetColor(COLOR_3DHIGHLIGHT));
			}
			else
			{
				CRect rcSeparator(rcItem.left + 28, rcItem.top, rcItem.right, rcItem.bottom);
				pClass->DrawThemeBackground(&dc, XTP_MP_POPUPSEPARATOR, 0, &rcSeparator);

			}
			continue;
		}

		if (bTheme)
		{
			if (bSelected)
			{
				pClass->DrawThemeBackground(&dc, XTP_MP_POPUPITEM, 2, &rcItem);
			}

			dc.SetTextColor(pMetrics->GetColor(!bEnabled ? COLOR_GRAYTEXT : COLOR_MENUTEXT));
		}
		else
		{
			if (bSelected)
			{
				dc.FillSolidRect(rcItem, pMetrics->GetColor(COLOR_HIGHLIGHT));
			}

			dc.SetTextColor(pMetrics->GetColor(!bEnabled ? COLOR_GRAYTEXT : bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT));
		}

		BOOL bDefault = pItem->IsDefault();
		CFont fontDefault;

		if (bDefault)
		{
			LOGFONT lf;
			pMetrics->m_fntMenu.GetLogFont(&lf);
			lf.lfWeight  = FW_BOLD;
			fontDefault.CreateFontIndirect(&lf);
			font.SetFont(&fontDefault);
		}

		CString strMenuText = pItem->GetText();
		int nFind = strMenuText.Find(_T('\t'));

		CSize szShortcut(0, 0);

		if (nFind != -1)
		{
			CString strShortcutText = strMenuText.Mid(nFind + 1);
			strMenuText.ReleaseBuffer(nFind);

			CRect rcShortcut(rcItem);
			rcShortcut.right -= 20;

			dc.DrawText(strShortcutText, rcShortcut, DT_VCENTER | DT_RIGHT | DT_SINGLELINE);
		}

		CRect rcText(rcItem);
		rcText.left += bTheme ? 33 : 17;

		dc.DrawText(strMenuText, rcText, DT_VCENTER | DT_LEFT | DT_SINGLELINE);

		if (pItem->GetPopupMenu())
		{
			if (bTheme)
			{
				CRect rcPopup(rcText.right - 16, rcText.top, rcText.right - 7, rcText.bottom);
				pClass->DrawThemeBackground(&dc, XTP_MP_POPUPSUBMENU, bEnabled ? 1 : 2, &rcPopup);
			}
			else
			{
				CPoint ptCenter(rcText.right - (bTheme ? 10 : 5), rcText.CenterPoint().y);
				XTPDrawHelpers()->Triangle(&dc, ptCenter, CPoint(ptCenter.x - 3, ptCenter.y - 3),
					CPoint(ptCenter.x - 3, ptCenter.y + 3), dc.GetTextColor());
			}
		}

		if (bDefault)
		{
			font.SetFont(&pMetrics->m_fntMenu);
		}

		BOOL bChecked = pItem->IsChecked();

		HBITMAP hbm = bChecked ? mii.hbmpChecked : mii.hbmpUnchecked;

		if (hbm)
		{
			BITMAP bmpInfo;
			::GetObject(hbm, sizeof(BITMAP), &bmpInfo);

			CXTPCompatibleDC dcBitmap(&dcPaint, hbm);

			dc.SetTextColor(0);
			dc.SetBkColor(0xFFFFFF);

			dc.BitBlt((bTheme ? 16 : 11) -  bmpInfo.bmWidth / 2 , (rcItem.top + rcItem.bottom - bmpInfo.bmHeight) / 2, bmpInfo.bmWidth, bmpInfo.bmHeight,
				&dcBitmap, 0, 0, SRCAND);
		}
		else if (bChecked)
		{
			if (bTheme)
			{
				CRect rcCheck(rcItem.left, rcItem.top, rcItem.left + 22, rcItem.bottom);

				pClass->DrawThemeBackground(&dc, XTP_MP_POPUPCHECKBACKGROUND, bEnabled ? 1 : 2, rcCheck);
				pClass->DrawThemeBackground(&dc, XTP_MP_POPUPCHECK, bEnabled ? 1 : 2, rcCheck);
			}
			else
			{
				CXTPPenDC pen (dc, dc.GetTextColor());
				CXTPBrushDC brush (dc, dc.GetTextColor());

				CPoint pt(rcItem.left + 5, rcItem.CenterPoint().y);
				CPoint pts[] = {pt, CPoint(pt.x + 2, pt.y + 2), CPoint(pt.x + 6, pt.y - 2),
					CPoint(pt.x + 6, pt.y), CPoint(pt.x + 2, pt.y + 4), CPoint(pt.x, pt.y + 2)};
				dc.Polygon(pts, _countof(pts));
			}
		}
		else
		{
			hbm = pItem->GetItemBitmap();

			int nSysBitmap = 0;

			switch ((UINT_PTR)hbm)
			{
				case (UINT_PTR)HBMMENU_POPUP_RESTORE: nSysBitmap = XTP_MP_SYSTEMRESTORE; break;
				case (UINT_PTR)HBMMENU_POPUP_MINIMIZE: nSysBitmap = XTP_MP_SYSTEMMINIMIZE; break;
				case (UINT_PTR)HBMMENU_POPUP_MAXIMIZE: nSysBitmap = XTP_MP_SYSTEMMAXIMIZE; break;
				case (UINT_PTR)HBMMENU_POPUP_CLOSE: nSysBitmap = XTP_MP_SYSTEMCLOSE; break;
			}

			if (nSysBitmap != 0)
			{
				if (bTheme)
				{
					CSize sz(20, 20);
					CRect rcBitmap(CPoint((bTheme ? 16 : 11) -  sz.cx / 2 , (rcItem.top + rcItem.bottom - sz.cy) / 2), sz);

					pClass->DrawThemeBackground(&dc, nSysBitmap, bEnabled ? 1 : 2, rcBitmap);
				}
				else
				{
					CSize sz(20, 20);
					CRect rcBitmap(CPoint((bTheme ? 16 : 11) -  sz.cx / 2 , (rcItem.top + rcItem.bottom - sz.cy) / 2 + 1), sz);

					CFont fontMarlett;
					fontMarlett.CreatePointFont(MulDiv(80, 96, dc.GetDeviceCaps(LOGPIXELSX)), _T("Marlett"));
					CFont* pFont = dc.SelectObject(&fontMarlett);
					dc.DrawText(nSysBitmap == XTP_MP_SYSTEMMINIMIZE ? _T("0") :
						nSysBitmap == XTP_MP_SYSTEMRESTORE ?  _T("2") :
						nSysBitmap == XTP_MP_SYSTEMMAXIMIZE ?  _T("1") :_T("r"),
						1, rcBitmap, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
					dc.SelectObject(pFont);
				}
			}
			else if (hbm)
			{
				BITMAP bmpInfo;
				::GetObject(hbm, sizeof(BITMAP), &bmpInfo);

				CXTPCompatibleDC dcBitmap(&dcPaint, hbm);

				dc.SetTextColor(0);
				dc.SetBkColor(0xFFFFFF);

				dc.BitBlt((bTheme ? 16 : 11) -  bmpInfo.bmWidth / 2 , (rcItem.top + rcItem.bottom - bmpInfo.bmHeight) / 2, bmpInfo.bmWidth, bmpInfo.bmHeight,
					&dcBitmap, 0, 0, SRCAND);

			}
		}
	}

}


//////////////////////////////////////////////////////////////////////////
// CXTPSkinPopupMenuState

CXTPSkinPopupMenuState::CXTPSkinPopupMenuState(HWND hWndNotify)
{
	m_bInsideMenuLoop = FALSE;
	m_bButtonDown = 0;
	m_bRightButton = FALSE;
	m_nFocus = focusMouse;
	m_hWndCapture = 0;
	m_bDismiss = FALSE;
	m_bNofyByPos = FALSE;
	m_pRootPopup = NULL;
	m_bNoNotify = FALSE;
	m_ptMouseLast = CPoint(0);
	m_nLastCommand = 0;

	m_bFirstClick = FALSE;
	m_bMenuStarted = FALSE;
	m_bSynchronous = FALSE;
	m_pAlternatePopup = NULL;

	CXTPSkinObject* pSkinObject = XTPSkinManager()->Lookup(hWndNotify);
	m_pSchema = pSkinObject ? pSkinObject->GetSchema() : XTPSkinManager()->GetSchema();

	m_dwMenuShowDelay = 400;
	SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &m_dwMenuShowDelay, 0);
}

void CXTPSkinPopupMenuState::InitMenu(CXTPSkinPopupMenu* pPopupMenu)
{
	m_pRootPopup = pPopupMenu;
	m_pRootPopup->InternalAddRef();

	m_bButtonDown = ((GetKeyState(VK_LBUTTON) & 0x8000) != 0);

	pPopupMenu->m_bDropNextPopup = FALSE;

	if (m_pRootPopup->m_hWndNotify && !m_bNoNotify)
	{
		SendMessage(m_pRootPopup->m_hWndNotify, WM_ENTERMENULOOP, 0, 0);
	}
}

#ifndef MNS_NOTIFYBYPOS
#define MNS_NOTIFYBYPOS     0x08000000
#define MIM_STYLE 0x00000010
#endif

int CXTPSkinPopupMenuState::GetMenuFlags(HMENU hMenu)
{
	struct XTP_MENUINFO
	{
		DWORD   cbSize;
		DWORD   fMask;
		DWORD   dwStyle;
		UINT    cyMax;
		HBRUSH  hbrBack;
		DWORD   dwContextHelpID;
		ULONG_PTR dwMenuData;
	};

	HMODULE hLib = GetModuleHandle(_T("USER32"));
	if (!hLib)
		return 0;

	typedef BOOL (WINAPI *PFNGETMENUINFO) (HMENU hmenu, XTP_MENUINFO* lpcmi);

	PFNGETMENUINFO pfnGetMenuInfo = (PFNGETMENUINFO)::GetProcAddress(hLib, "GetMenuInfo");
	if (!pfnGetMenuInfo)
		return 0;

	XTP_MENUINFO mi;
	ZeroMemory(&mi, sizeof(mi));
	mi.cbSize = sizeof(mi);
	mi.fMask = MIM_STYLE;

	if (!(*pfnGetMenuInfo)(hMenu, &mi))
		return FALSE;

	return mi.dwStyle;
}

BOOL CXTPSkinPopupMenuState::StartMenu(MenuFocus nFocus)
{
	m_bMenuStarted = TRUE;

	m_nFocus = nFocus;

	m_pRootPopup->m_bToggle = FALSE;
	m_pRootPopup->m_bAboutToHide = FALSE;

	HWND hWndNotify = m_pRootPopup->m_hWndNotify;

	m_hWndCapture= hWndNotify;
	::SetCapture(m_hWndCapture);
	::SendMessage(hWndNotify, WM_SETCURSOR, (WPARAM)hWndNotify, MAKELONG(MSGF_MENU, 0));

	if (m_pRootPopup->m_bMenuBar)
	{
		// TODO GetSysMenu from Child xxxGetInitMenuParam
		BOOL bSystemMenu = m_pRootPopup->m_bSysMenu;

		if (!bSystemMenu)
		{
			HMENU hMenu = ::GetSystemMenu(hWndNotify, FALSE);
			if (hMenu)
			{
				::SetMenuDefaultItem(hMenu, SC_CLOSE, MF_BYCOMMAND);
				m_pAlternatePopup = new CXTPSkinPopupMenu();
				m_pAlternatePopup->m_hMenu = hMenu;
				m_pAlternatePopup->m_hWnd = hWndNotify;
				m_pAlternatePopup->m_hWndNotify = hWndNotify;
				m_pAlternatePopup->m_bSysMenu = TRUE;
				m_pAlternatePopup->m_bMenuBar = TRUE;
				m_pAlternatePopup->PositionSysMenu();
				m_pAlternatePopup->m_pState = this;
			}
		}
	}

	int nFlags = GetMenuFlags(m_pRootPopup->m_hMenu);

	if (nFlags & MNS_NOTIFYBYPOS)
		m_bNofyByPos = TRUE;

	if (!m_bNoNotify && hWndNotify)
	{
		::SendMessage(hWndNotify, WM_INITMENU, (WPARAM)m_pRootPopup->m_hMenu, 0);
	}

	// TODO: Add EVENT_SYSTEM_MENUSTART WinEvent.

	return TRUE;
}


#define MENU_NOITEM (int)-1

int CXTPSkinPopupMenuState::ItemHitTest(CPoint point, CXTPSkinPopupMenu* pPopupMenu)
{
	for (int i = 0; i < pPopupMenu->GetCount(); i++)
	{
		CXTPSkinPopupMenuItem* pItem = pPopupMenu->m_arrItems.GetAt(i);

		CRect rcItem(pItem->m_rcItem);

		WindowToScreen(pPopupMenu->m_hWnd, rcItem);

		if (rcItem.PtInRect(point))
			return i;
	}
	return MENU_NOITEM;
}

void CXTPSkinPopupMenuState::WindowToScreen(HWND hWnd, CRect& rcItem)
{
	CXTPWindowRect rcWindow(hWnd);

	if (GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL )
	{
		rcItem.OffsetRect(rcWindow.right - rcItem.right - rcItem.left, rcWindow.top);
	}
	else
	{
		rcItem.OffsetRect(rcWindow.TopLeft());
	}
}

CXTPSkinPopupMenu* CXTPSkinPopupMenuState::FindMenu(CPoint point, CXTPSkinPopupMenu* pPopupMenu, int* pnItem)
{
	*pnItem = 0;

	if (pPopupMenu->m_pNextPopup)
	{
		CXTPSkinPopupMenu* lResult = FindMenu(point, pPopupMenu->m_pNextPopup, pnItem);
		if (lResult)
		{
			return lResult;
		}
	}

	if (pPopupMenu->m_bMenuBar)
	{
		HWND hWnd = pPopupMenu->m_hWndNotify;

		if (pPopupMenu->m_bSysMenu)
		{
			HICON hIcon = m_pSchema->GetFrameSmIcon(hWnd);
			if (!hIcon)
				return NULL;

			CXTPWindowRect rcWindow(hWnd);

			if (GetWindowLong(hWnd, GWL_STYLE) & WS_MINIMIZE)
			{
				if (rcWindow.PtInRect(point))
					return pPopupMenu;
				return NULL;
			}

			CRect rcIcon(pPopupMenu->GetItem(0)->m_rcItem);
			WindowToScreen(hWnd, rcIcon);

			if (rcIcon.PtInRect(point))
			{
				*pnItem = 0;
				return pPopupMenu;
			}

			if (m_pAlternatePopup && m_pAlternatePopup != pPopupMenu)
			{
				int nHitTest = CXTPSkinPopupMenuState::ItemHitTest(point, m_pAlternatePopup);
				if (nHitTest != MENU_NOITEM)
				{
					*pnItem = nHitTest;
					return m_pAlternatePopup;
				}
			}

			return NULL;
		}
		else
		{
			if (GetWindowLong(hWnd, GWL_STYLE) & WS_MINIMIZE)
				return NULL;
		}

	}
	else
	{
		CXTPWindowRect rc(pPopupMenu->m_hWnd);
		if (!rc.PtInRect(point))
			return NULL;
	}

	int nHitTest = CXTPSkinPopupMenuState::ItemHitTest(point, pPopupMenu);

	if (pPopupMenu->m_bMenuBar)
	{
		if (nHitTest == MENU_NOITEM)
		{
			if (m_pAlternatePopup && m_pAlternatePopup != pPopupMenu)
			{
				CXTPSkinPopupMenu* pAlternatePopup = FindMenu(point, m_pAlternatePopup, pnItem);

				if (pAlternatePopup)
					return pAlternatePopup;
			}
			return NULL;
		}
	}

	*pnItem = nHitTest;
	return pPopupMenu;
}

BOOL CXTPSkinPopupMenuState::SetTimerToCloseHierarchy(CXTPSkinPopupMenu* pPopupMenu)
{
	CXTPSkinPopupMenu* pNextPopup = GetNextPopup(pPopupMenu);

	if (!pNextPopup)
		return FALSE;

	if (pPopupMenu->m_nHideTimer)
		return TRUE;

	if (!SetTimer(pPopupMenu->m_hWnd, TIMERID_MENUHIDE, m_dwMenuShowDelay, NULL))
		return FALSE;

	pPopupMenu->m_nHideTimer = TIMERID_MENUHIDE;

	pNextPopup->m_bAboutToHide = TRUE;

	return TRUE;
}

BOOL CXTPSkinPopupMenuState::SetTimerToOpenHierarchy(CXTPSkinPopupMenu* pPopupMenu)
{
	ASSERT(!pPopupMenu->m_bMenuBar);

	CXTPSkinPopupMenuItem* pItem = pPopupMenu->GetItem(pPopupMenu->m_nSelected);
	if (!pItem)
		return FALSE;

	if (pPopupMenu->m_nShowTimer || pPopupMenu->m_nSelected == pPopupMenu->m_nDropped)
		return 1;

	if (!SetTimer(pPopupMenu->m_hWnd, TIMERID_MENUSHOW, m_dwMenuShowDelay, NULL))
		return FALSE;

	pPopupMenu->m_nShowTimer = TIMERID_MENUSHOW;

	return TRUE;
}

void CXTPSkinPopupMenuState::RedrawPopup(CXTPSkinPopupMenu* pPopupMenu)
{
	if (pPopupMenu->m_bMenuBar) ::SendMessage(pPopupMenu->m_hWnd, WM_NCPAINT, 0, 0); else ::InvalidateRect(pPopupMenu->m_hWnd, 0, FALSE);
}

void CXTPSkinPopupMenuState::SendMenuSelect(CXTPSkinPopupMenu* pPopupMenu)
{
	UINT dwFlags = 0;
	UINT nCommand = 0;
	int nIndex = -1;

	CXTPSkinPopupMenuItem* pItem = pPopupMenu->GetItem(pPopupMenu->m_nSelected);
	if (pItem)
	{
		dwFlags = pItem->GetType() | pItem->GetState();
		nIndex = pItem->m_nItem;

		if (pItem->GetPopupMenu())
			dwFlags |= MF_POPUP;

		if (dwFlags & MF_POPUP)
			nCommand = nIndex;
		else
			nCommand = pItem->GetID();

		if (m_nFocus == focusMouse)
			dwFlags |= MF_MOUSESELECT;

		if (pPopupMenu->m_bSysMenu)
			dwFlags |= MF_SYSMENU;

	}

	::SendMessage(pPopupMenu->m_hWndNotify, WM_MENUSELECT, (DWORD)MAKELONG(nCommand, dwFlags), (LPARAM)pPopupMenu->m_hMenu);

}

CXTPSkinPopupMenuItem* CXTPSkinPopupMenuState::SelectItem(CXTPSkinPopupMenu* pPopupMenu, int nItem)
{
	if (pPopupMenu->m_nSelected == nItem)
	{
		return pPopupMenu->GetItem(nItem);
	}

	if (pPopupMenu->m_nShowTimer)
	{
		KillTimer(pPopupMenu->m_hWnd, pPopupMenu->m_nShowTimer);
		pPopupMenu->m_nShowTimer = 0;
	}

	if (pPopupMenu->m_bAboutToHide && pPopupMenu->m_pPrevPopup)
	{
		CXTPSkinPopupMenu* pPrevPopup = pPopupMenu->m_pPrevPopup;

		if (pPrevPopup->m_nHideTimer)
		{
			::KillTimer(pPrevPopup->m_hWnd, pPrevPopup->m_nHideTimer);
			pPrevPopup->m_nHideTimer = NULL;
		}

		if (pPrevPopup->m_nShowTimer)
		{
			::KillTimer(pPrevPopup->m_hWnd, pPrevPopup->m_nShowTimer);
			pPrevPopup->m_nShowTimer = NULL;
		}

		if (pPrevPopup->m_nSelected != pPrevPopup->m_nDropped)
		{
			pPrevPopup->m_nSelected = pPrevPopup->m_nDropped;
			RedrawPopup(pPrevPopup);
			SendMenuSelect(pPrevPopup);
		}

		pPopupMenu->m_bAboutToHide = FALSE;
	}

	if (pPopupMenu->m_nSelected != MENU_NOITEM)
	{
		if (GetNextPopup(pPopupMenu))
		{
			if (pPopupMenu->m_bMenuBar)
			{
				CloseHierarchy(pPopupMenu);
			}
			else
			{
				SetTimerToCloseHierarchy(pPopupMenu);
			}
		}
	}

	pPopupMenu->m_nSelected = nItem;

	RedrawPopup(pPopupMenu);

	SendMenuSelect(pPopupMenu);

	return pPopupMenu->GetItem(nItem);
}

CPoint CXTPSkinPopupMenuState::PositionHierarchy(CXTPSkinPopupMenu* pSubMenu, CXTPSkinPopupMenu* pPopupMenu, CRect rcItem, CSize sz)
{
	CPoint pt(pPopupMenu->m_bMenuBar ? rcItem.left : rcItem.right - 3, pPopupMenu->m_bMenuBar ? rcItem.bottom : rcItem.top - 3);
	CRect rcMonitor(XTPMultiMonitor()->GetScreenArea(pt));

	if (pPopupMenu->m_bMenuBar)
	{
		BOOL bMinimized = (GetWindowLong(pPopupMenu->m_hWnd, GWL_STYLE) & WS_MINIMIZE) != 0;

		if (bMinimized)
		{
			pt.y = rcItem.top - sz.cy;
			if (pt.y < rcMonitor.top) pt.y = rcItem.bottom;
		}

		if (GetWindowLong(pPopupMenu->m_hWnd, GWL_EXSTYLE) & (WS_EX_LAYOUTRTL | WS_EX_RIGHT))
		{
			pt.x = rcItem.right - sz.cx;
			pSubMenu->m_bDroppedLeft = TRUE;
		}
		pt.x = min(pt.x, rcMonitor.right - sz.cx);
	}
	else
	{
		if (pPopupMenu->m_bDroppedLeft)
		{
			int x = rcItem.left + 3 - sz.cx;
			if (x >= rcMonitor.left)
			{
				pt.x = x;
				pSubMenu->m_bDroppedLeft = TRUE;
			}
		}

		if (pt.x + sz.cx > rcMonitor.right)
		{
			pt.x = rcItem.left + 3 - sz.cx;
			pSubMenu->m_bDroppedLeft = TRUE;
		}
	}

	if (pt.y + sz.cy > rcMonitor.bottom)
	{
		pt.y -= sz.cy;

		if (pPopupMenu->m_bMenuBar)
		{
			pt.y -= GetSystemMetrics(SM_CYMENUSIZE);
		}
		else
		{
			pt.y += rcItem.Height() + 3;
		}

		if ((pt.y < rcMonitor.top) || (pt.y + sz.cy > rcMonitor.bottom))
			pt.y = rcMonitor.bottom - sz.cy;
	}

	pt.x = max(pt.x, rcMonitor.left);
	pt.y = max(pt.y, rcMonitor.top);

	CRect rcPopup(pt.x, pt.y, pt.x + sz.cx, pt.y + sz.cy);
	rcPopup.DeflateRect(3, 3);

	if (CRect().IntersectRect(rcItem, rcPopup))
	{
		if ((rcItem.right + sz.cx) <= rcMonitor.right)
			pt.x = rcItem.right;
		else if ((rcItem.left - sz.cx) >= rcMonitor.left)
			pt.x = rcItem.left - sz.cx;
	}



	return pt;
}

HWND CXTPSkinPopupMenuState::OpenHierarchy(CXTPSkinPopupMenu* pPopupMenu)
{
	if (pPopupMenu->m_nSelected < 0 || pPopupMenu->m_nSelected >= pPopupMenu->GetCount())
		return NULL;

	if (GetNextPopup(pPopupMenu))
	{
		if (pPopupMenu->m_nHideTimer)
		{
			CloseHierarchy(pPopupMenu);
		}
		else
		{
			return NULL;
		}
	}

	if (pPopupMenu->m_nShowTimer)
	{
		KillTimer(pPopupMenu->m_hWnd, pPopupMenu->m_nShowTimer);
		pPopupMenu->m_nShowTimer = 0;
	}

	CXTPSkinPopupMenuItem* pItem = pPopupMenu->GetItem(pPopupMenu->m_nSelected);

	HMENU hSubMenu = pItem->GetPopupMenu();
	if (!hSubMenu)
		return NULL;

	BOOL bSendNotify = FALSE;

	HWND hwndResult = NULL;

	TRY
	{
		if (pPopupMenu->m_hWndNotify && !m_bNoNotify)
		{
			SendMessage(pPopupMenu->m_hWndNotify, WM_INITMENUPOPUP, (WPARAM)hSubMenu, MAKELONG(pPopupMenu->m_nSelected, pPopupMenu->m_bSysMenu ? 1 : 0));

			bSendNotify = TRUE;
		}

		if (!m_bInsideMenuLoop)
			AfxThrowMemoryException();

		if (pPopupMenu->m_nSelected < 0 || pPopupMenu->m_nSelected >= pPopupMenu->GetCount())
			AfxThrowMemoryException();

		pItem = pPopupMenu->GetItem(pPopupMenu->m_nSelected);

		if (!pItem->IsEnabled() || !pItem->GetPopupMenu() || GetMenuItemCount(pItem->GetPopupMenu()) == 0)
			AfxThrowMemoryException();



		CXTPSkinPopupMenu* pSubMenu = new CXTPSkinPopupMenu();
		pSubMenu->m_pState = this;

		if (!pSubMenu->Create(pPopupMenu->m_hWndNotify))
		{
			pSubMenu->InternalRelease();
			AfxThrowMemoryException();
		}

		pSubMenu->m_hMenu = hSubMenu;
		pSubMenu->m_hWndNotify = pPopupMenu->m_hWndNotify;
		pSubMenu->m_bSysMenu = pPopupMenu->m_bSysMenu;

		bSendNotify = FALSE;
		pSubMenu->m_bSendUninit = TRUE;

		pPopupMenu->m_pNextPopup = pSubMenu;
		pSubMenu->m_pPrevPopup = pPopupMenu;

		if (pPopupMenu->m_bMenuBar)
		{
			pPopupMenu->m_bDropNextPopup = TRUE;
		}

		if (pPopupMenu->m_hWndNotify)
		{
			UpdateWindow(pPopupMenu->m_hWndNotify);
		}

		CSize size = pSubMenu->RecalcLayout();

		CRect rcItem = pItem->GetScreenPos();

		CPoint pt = PositionHierarchy(pSubMenu, pPopupMenu, rcItem, size);

		PlayEventSound(xtpSoundMenuPopup);

		::SetWindowPos(pSubMenu->m_hWnd, HWND_TOPMOST, pt.x, pt.y, size.cx, size.cy, SWP_SHOWWINDOW | SWP_NOOWNERZORDER | SWP_NOACTIVATE);

		if (m_nFocus == focusKeyboard)
		{
			SelectItem(pSubMenu, 0);
		}

		pPopupMenu->m_nDropped = pPopupMenu->m_nSelected;

		UpdateWindow(pSubMenu->m_hWnd);

		hwndResult = pSubMenu->m_hWnd;

	}
	CATCH (CMemoryException, e)
	{
	}
	END_CATCH

	if (bSendNotify)
	{
		SendMessage(pPopupMenu->m_hWndNotify, WM_UNINITMENUPOPUP, (WPARAM)hSubMenu, MAKELONG(0, pPopupMenu->m_bSysMenu ? 1 : 0));
	}


	return hwndResult;
}

void CXTPSkinPopupMenuState::CloseHierarchy(CXTPSkinPopupMenu* pPopupMenu)
{
	if (pPopupMenu->m_nHideTimer)
	{
		::KillTimer(pPopupMenu->m_hWnd, pPopupMenu->m_nHideTimer);
		pPopupMenu->m_nHideTimer = 0;
	}

	CXTPSkinPopupMenu* pNextPopup = GetNextPopup(pPopupMenu);

	if (pNextPopup)
	{
		CloseHierarchy(pNextPopup);

		if (!pNextPopup->m_bMenuBar)
		{
			if (pNextPopup->m_bSendUninit && !m_bNoNotify)
			{
				SendMessage(pNextPopup->m_hWndNotify, WM_UNINITMENUPOPUP,
					(WPARAM)pNextPopup->m_hMenu, MAKELONG(0, pNextPopup->m_bSysMenu ? MF_SYSMENU: 0));
			}

			pNextPopup->DestroyWindow();
			pNextPopup->InternalRelease();
		}

		pPopupMenu->m_pNextPopup = NULL;
		pPopupMenu->m_nDropped = MENU_NOITEM;
	}

	if (pPopupMenu->m_nSelected != MENU_NOITEM)
	{
		SendMenuSelect(pPopupMenu);
	}

}


CXTPSkinPopupMenu* CXTPSkinPopupMenuState::GetNextPopup(CXTPSkinPopupMenu* pPopupMenu) const
{
	return pPopupMenu->m_pNextPopup;
}

CXTPSkinPopupMenu* CXTPSkinPopupMenuState::GetActivePopup() const
{
	CXTPSkinPopupMenu* pActivePopup = m_pRootPopup;

	while (pActivePopup->m_pNextPopup != NULL)
	{
		pActivePopup = pActivePopup->m_pNextPopup;
	}

	return pActivePopup;
}

BOOL CXTPSkinPopupMenuState::HideNextHierarchy(CXTPSkinPopupMenu* pPopupMenu)
{
	CXTPSkinPopupMenu* pNextPopup = GetNextPopup(pPopupMenu);
	if (pNextPopup)
	{
		if (GetNextPopup(pPopupMenu) != GetActivePopup())
			CloseHierarchy(pNextPopup);

		SelectItem(pNextPopup, -1);
		return TRUE;
	}

	return FALSE;
}

void CXTPSkinPopupMenuState::DismissNotify(CXTPSkinPopupMenu* pPopupMenu, int nItem)
{
	DismissNotify(pPopupMenu->m_hMenu, nItem);
}

void CXTPSkinPopupMenuState::DismissNotify(HMENU hMenu, int nItem)
{
	if (nItem < 0 || nItem >= GetMenuItemCount(hMenu))
		return;

	UINT nMessage = 0;
	UINT nCommand = 0;
	LPARAM lParam = 0;

	if (m_pRootPopup->m_bSysMenu)
	{
		nMessage = WM_SYSCOMMAND;
		nCommand = ::GetMenuItemID(hMenu, nItem);
	}
	else if (m_bNofyByPos)
	{
		nMessage = WM_MENUCOMMAND;
		nCommand = nItem;
		lParam = (LPARAM)hMenu;
	}
	else
	{
		nMessage = WM_COMMAND;
		nCommand =  ::GetMenuItemID(hMenu, nItem);
	}

	Notify(nMessage, nCommand, lParam);
}

void CXTPSkinPopupMenuState::OnButtonUp(CXTPSkinPopupMenu* pPopupMenu, int nItem)
{
	if (!m_bButtonDown)
		return;

	if (nItem == MENU_NOITEM)
		return;

	if (nItem != pPopupMenu->m_nSelected)
		return;

	if (pPopupMenu->m_bMenuBar)
	{
		if (GetNextPopup(pPopupMenu))
		{
			if (!pPopupMenu->m_bToggle)
				return;

			pPopupMenu->m_bToggle = FALSE;
			Dismiss();
			return;
		}

	}
	else if (pPopupMenu->m_nShowTimer)
	{
		pPopupMenu->m_bToggle = FALSE;
		OpenHierarchy(pPopupMenu);
		return;
	}

	CXTPSkinPopupMenuItem* pItem = pPopupMenu->GetItem(pPopupMenu->m_nSelected);
	if (!pItem)
		return;

	if (!pItem->IsSeparator() && pItem->IsEnabled() && !pItem->GetPopupMenu())
	{
		DismissNotify(pPopupMenu, pPopupMenu->m_nSelected);
	}
}

void CXTPSkinPopupMenuState::OnButtonDblClick(CXTPSkinPopupMenu* pPopupMenu, int nItem)
{
	CXTPSkinPopupMenuItem* pItem = pPopupMenu->GetItem(nItem);
	if (!pItem)
		return;

	if (!pItem->IsEnabled())
		return;

	HMENU hMenu = pItem->GetPopupMenu();
	if (hMenu)
	{
		nItem = GetMenuDefaultItem(hMenu, MF_BYPOSITION, 0);
		if (nItem == -1)
			return;
	}
	else
	{
		hMenu = pPopupMenu->m_hMenu;
	}

	DismissNotify(hMenu, nItem);
}

void CXTPSkinPopupMenuState::OnButtonDown(CXTPSkinPopupMenu* pPopupMenu, int nItem, BOOL bClick)
{
	if (pPopupMenu->m_nSelected != nItem)
	{
		BOOL bOpenPopup = FALSE;

		if (bClick)
		{
			bOpenPopup = TRUE;
			pPopupMenu->m_bToggle = FALSE;

		}
		else
		{
			bOpenPopup = pPopupMenu->m_bDropNextPopup;
		}

		CXTPSkinPopupMenuItem* pItem = SelectItem(pPopupMenu, nItem);

		if (pItem && pItem->GetPopupMenu() && bOpenPopup)
		{
			if (!OpenHierarchy(pPopupMenu))
				return;
		}
	}
	else
	{
		if (bClick) pPopupMenu->m_bToggle = TRUE;

		if (!HideNextHierarchy(pPopupMenu) && bClick && OpenHierarchy(pPopupMenu))
			pPopupMenu->m_bToggle = FALSE;
	}

	if (bClick)
	{
		m_bButtonDown = TRUE;
	}
}

void CXTPSkinPopupMenuState::Dismiss()
{
	Notify(0, 0, 0);
}

void CXTPSkinPopupMenuState::Notify(UINT nMessage, UINT nCommand, LPARAM lParam)
{
	if (m_bDismiss)
		return;

	m_bDismiss = TRUE;
	m_bInsideMenuLoop = FALSE;
	m_bButtonDown = FALSE;

	CloseHierarchy(m_pRootPopup);
	SelectItem(m_pRootPopup, MENU_NOITEM);

	ReleaseCapture();

	HWND hWndNotify = m_pRootPopup->m_hWndNotify;

	if (hWndNotify == 0)
		return;

	if (!m_pRootPopup->m_bMenuBar)
	{
		CloseHierarchy(m_pRootPopup);
		m_pRootPopup->DestroyWindow();
	}

	if (!m_bNoNotify)
	{
		SendMessage(hWndNotify, WM_EXITMENULOOP, 0, 0);
	}

	m_nLastCommand = nCommand;

	if (nMessage != 0)
	{
		PlayEventSound(xtpSoundMenuCommand);

		if (!m_bSynchronous)
		{
			SendMessage(hWndNotify, nMessage, nCommand, lParam);

			if (nMessage == WM_SYSCOMMAND && IsWindow(hWndNotify))
			{
				::SendMessage(hWndNotify, WM_NCPAINT, 0, 0);
			}
		}
	}
}

void CXTPSkinPopupMenuState::OnMouseMove(CPoint point)
{
   if (point == m_ptMouseLast)
		return;

	m_ptMouseLast = point;

	int nItem;
	CXTPSkinPopupMenu* pMenuHit = FindMenu(point, m_pRootPopup, &nItem);

	if (m_nFocus == focusKeyboard)
	{
		if (pMenuHit == NULL)
			return;

		m_nFocus = focusMouse;
	}

	if (pMenuHit == m_pAlternatePopup)
	{
		if (m_bButtonDown)
		{
			SwitchToAlternateMenu();
		}
		else
		{
			pMenuHit = NULL;
		}

	}

	if (pMenuHit)
	{
		if (pMenuHit->m_bMenuBar)
		{
			OnButtonDown(pMenuHit, nItem, FALSE);
		}
		else
		{
			CXTPSkinPopupMenuItem* pItem = SelectItem(pMenuHit, nItem);
			if (pItem && pItem->GetPopupMenu() && pItem->IsEnabled())
			{
				if (!SetTimerToOpenHierarchy(pMenuHit))
				{
					HideNextHierarchy(pMenuHit);
				}
			}
		}
	}
	else
	{
		SelectItem(GetActivePopup(), MENU_NOITEM);
	}

}

CXTPSkinPopupMenu* CXTPSkinPopupMenuState::FindPopup(HWND hWnd) const
{
	CXTPSkinPopupMenu* pPopupMenu = m_pRootPopup;
	while (pPopupMenu)
	{
		if (pPopupMenu->m_hWnd == hWnd)
			return pPopupMenu;

		pPopupMenu = GetNextPopup(pPopupMenu);
	}

	return NULL;
}

BOOL CXTPSkinPopupMenuState::RemoveMessage(UINT nMessage)
{
	MSG msg;
	if (!PeekMessage(&msg, NULL, 0, 0, PM_NOYIELD | PM_NOREMOVE))
	{
		return FALSE;
	}

	if (msg.message == nMessage)
	{
		PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
		return TRUE;
	}

	return FALSE;
}

int CXTPSkinPopupMenuState::FindNextItem(CXTPSkinPopupMenu* pPopupMenu, int nItem, BOOL bForward, UINT nFlags) const
{
	int nCount = pPopupMenu->GetCount();
	int nStart = nItem;

	if ((nItem < 0) && bForward)
		// going forward from beginning -- stop after last menu item
		nItem = nStart = nCount;
	else if ((nItem >= nCount) && (!bForward))
		// going backward from end -- stop after first menu item
		nItem = nStart = -1;


	if (!nCount)
		return MENU_NOITEM;

	BOOL bFirst = TRUE;

	for (;;)
	{
		nItem += bForward ? +1 : -1;

		if (nItem == nStart && !bFirst)
			return MENU_NOITEM;

		if (nItem >= nCount)
		{
			if (nFlags)
				return MENU_NOITEM;

			nItem = -1;
			continue;
		}
		else if (nItem < 0)
		{
			if (nFlags)
				return MENU_NOITEM;

			nItem = nCount;
			continue;
		}

		bFirst = FALSE;

		CXTPSkinPopupMenuItem* pItem = pPopupMenu->GetItem(nItem);

		if (pItem->IsSeparator())
			continue;

		if (pPopupMenu->m_bMenuBar && !pPopupMenu->m_bSysMenu && pItem->IsMDISysButton())
			continue;

		break;
	}

	return nItem;
}

void CXTPSkinPopupMenuState::OnKeyDown(CXTPSkinPopupMenu* pPopupMenu, WPARAM nKey)
{
	if (m_bButtonDown)
		return;

	switch (nKey)
	{
		case VK_MENU:
		case VK_F10:
			Dismiss();
			return;

		case VK_ESCAPE:

			if (pPopupMenu->m_bMenuBar || pPopupMenu == m_pRootPopup || pPopupMenu->m_pPrevPopup == NULL)
			{
				Dismiss();
			}
			else
			{
				CXTPSkinPopupMenu* pPrevPopup = pPopupMenu->m_pPrevPopup;
				CloseHierarchy(pPrevPopup);

				pPrevPopup->m_bDropNextPopup = FALSE;
			}
			return;

		case VK_UP:
		case VK_DOWN:

			if (pPopupMenu->m_bMenuBar)
			{
				OpenHierarchy(pPopupMenu);
			}
			else
			{
				int nItem = FindNextItem(pPopupMenu, pPopupMenu->m_nSelected, (nKey == VK_UP ? FALSE : TRUE), 0);
				SelectItem(pPopupMenu, nItem);
			}

			return;

		case VK_LEFT:
		case VK_RIGHT:
			{
				int nScreenKey = GetWindowLong(pPopupMenu->m_hWnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL ? (nKey == VK_LEFT ? VK_RIGHT : VK_LEFT) : (int)nKey;

				if (!pPopupMenu->m_bMenuBar && nScreenKey == VK_RIGHT && !GetNextPopup(pPopupMenu))
				{
					if (OpenHierarchy(pPopupMenu))
						return;
				}
				BOOL bHierarchyWasDropped = FALSE;

				if (GetNextPopup(pPopupMenu))
				{
					bHierarchyWasDropped = TRUE;

					if (nScreenKey == VK_LEFT && !pPopupMenu->m_bMenuBar)
					{
						CloseHierarchy(pPopupMenu);
						return;
					}
				}
				else
				{
					if (pPopupMenu->m_bDropNextPopup) bHierarchyWasDropped = TRUE;
				}


				if (pPopupMenu->m_pPrevPopup)
				{
					OnKeyDown(pPopupMenu->m_pPrevPopup, nKey);
					return;
				}

				if (pPopupMenu->m_bMenuBar)
				{
					int nItem = FindNextItem(pPopupMenu, pPopupMenu->m_nSelected, (nScreenKey == VK_RIGHT  ? TRUE : FALSE), 1);

					if (nItem == MENU_NOITEM)
					{
						if (m_pAlternatePopup)
						{
							if (SwitchToAlternateMenu())
							{
								pPopupMenu = m_pRootPopup;
								nItem = FindNextItem(pPopupMenu, MENU_NOITEM, (nScreenKey == VK_RIGHT ? TRUE : FALSE), 0);
							}
						}

					}

					if (nItem != MENU_NOITEM)
					{
						if (GetNextPopup(pPopupMenu))
						{
							CloseHierarchy(pPopupMenu);
						}

						SelectItem(pPopupMenu, nItem);

						if (bHierarchyWasDropped)
						{
							OpenHierarchy(pPopupMenu);
						}
					}
				}
			}
			return;

		case VK_RETURN:
			{
				CXTPSkinPopupMenuItem* pItem = pPopupMenu->GetItem(pPopupMenu->m_nSelected);
				if (!pItem)
					return;

				if (!pItem->IsEnabled())
				{
					Dismiss();
					return;
				}

				if (pItem->GetPopupMenu())
				{
					OpenHierarchy(pPopupMenu);
					return;
				}

				DismissNotify(pPopupMenu, pPopupMenu->m_nSelected);

			}
			return;
	}
}

int CXTPSkinPopupMenuState::FindChar(CXTPSkinPopupMenu* pPopupMenu, WPARAM nKey, int nItem)
{
	if (!nKey)
		return MENU_NOITEM;

	CString sKey((TCHAR)nKey);
	sKey.MakeLower();

	int nResult = MENU_NOITEM;
	int nFirst = MENU_NOITEM;

	int nStart = nItem;

	if (nStart < 0)
		nStart = FindNextItem(pPopupMenu, -1, FALSE, 0);

	do
	{
		int nPrev = nItem;

		nItem = FindNextItem(pPopupMenu, nItem, TRUE, 0);
		if (nItem == MENU_NOITEM || nItem == nFirst)
			break;

		if (nFirst == MENU_NOITEM)
			nFirst = nItem;

		CString str = pPopupMenu->GetMenuString(nItem);
		if (!str.IsEmpty())
		{
			str.MakeLower();

			int nIndex = str.Find(_T('&'));
			if (nIndex == -1)
			{
				if (str[0] == sKey[0] && nResult == MENU_NOITEM)
					nResult = nItem;
			}
			else
			{
				if (str[nIndex + 1] == sKey[0])
				{
					return nItem;
				}
			}
		}

		if (nItem == nPrev)
			break;

	} while (nItem != nStart);

	return nResult;
}

void CXTPSkinPopupMenuState::OnChar(CXTPSkinPopupMenu* pPopupMenu, WPARAM nKey)
{
	int nItem = FindChar(pPopupMenu, nKey, pPopupMenu->m_nSelected);
	BOOL bExecute = FALSE;

	if (nItem != MENU_NOITEM)
	{
		int nFirstItem = nItem;

		while (!pPopupMenu->GetItem(nItem)->IsEnabled())
		{
			nItem = FindChar(pPopupMenu, nKey, nItem);

			if (nItem == nFirstItem)
			{
				Dismiss();
				return;
			}
		}
		int nItemExecute = nItem;

		do
		{
			nItem = FindChar(pPopupMenu, nKey, nItem);

		} while (!pPopupMenu->GetItem(nItem)->IsEnabled() && (nItem != nFirstItem));

		if (nFirstItem == nItem || nItem == nItemExecute)
			bExecute = TRUE;

		nItem = nItemExecute;
	}

	if (nItem == MENU_NOITEM && pPopupMenu->m_bMenuBar && nKey == ' ')
	{
		if (pPopupMenu->m_bSysMenu)
		{
			nItem = 0;
			bExecute = TRUE;
		}
		else if (m_pAlternatePopup)
		{
			if (SwitchToAlternateMenu())
			{
				OnChar(m_pRootPopup, nKey);
			}
			return;
		}
	}

	if (nItem == MENU_NOITEM && pPopupMenu->m_bMenuBar && m_pAlternatePopup && m_pAlternatePopup != pPopupMenu)
	{
		nItem = FindChar(m_pAlternatePopup, nKey, 0);
		if (nItem != MENU_NOITEM)
		{
			if (SwitchToAlternateMenu())
			{
				OnChar(m_pRootPopup , nKey);
			}
			return;
		}
	}

	if (nItem == MENU_NOITEM && pPopupMenu->m_hWndNotify && !m_bNoNotify)
	{
		int nFlag = (pPopupMenu->m_bSysMenu ? MF_SYSMENU : 0) | (pPopupMenu->m_bMenuBar ? 0 : MF_POPUP);

		LRESULT lResult = ::SendMessage(pPopupMenu->m_hWndNotify, WM_MENUCHAR, MAKELONG((WORD)nKey, (WORD)nFlag), (LPARAM)pPopupMenu->m_hMenu);

		switch (HIWORD(lResult))
		{
		case MNC_IGNORE:
			MessageBeep(0);

			if (nFlag & MF_POPUP)
				return;

			Dismiss();
			return;

		case MNC_CLOSE:
			Dismiss();
			return;

		case MNC_EXECUTE:
			bExecute = TRUE;

		case MNC_SELECT:
			nItem = (short)LOWORD(lResult);
			if (nItem < 0 || nItem < pPopupMenu->GetCount())
				return;

			break;
		}
	}

	if (nItem != MENU_NOITEM)
	{
		SelectItem(pPopupMenu, nItem);

		if (bExecute)
		{
			OnKeyDown(pPopupMenu, VK_RETURN);
		}
	}
}

BOOL CXTPSkinPopupMenuState::SwitchToAlternateMenu()
{
	if (!m_pRootPopup->m_bMenuBar || !m_pAlternatePopup)
		return FALSE;

	SelectItem(m_pRootPopup, MENU_NOITEM);

	CXTPSkinPopupMenu* pAlternatePopup = m_pAlternatePopup;
	m_pAlternatePopup = m_pRootPopup;
	m_pRootPopup = pAlternatePopup;

	m_pRootPopup->m_bDropNextPopup = m_pAlternatePopup->m_bDropNextPopup;

	return TRUE;
}

BOOL CXTPSkinPopupMenuState::HandleMenuMessage(LPMSG lpMsg)
{
	switch (lpMsg->message)
	{
		case WM_RBUTTONDOWN:
		case WM_NCRBUTTONDOWN:
			if (!m_bRightButton)
			{
				m_nFocus = CXTPSkinPopupMenuState::focusMouse;
				CPoint point;
				GetCursorPos(&point);

				int nItem = 0;
				CXTPSkinPopupMenu* pMenuHit = FindMenu(point, m_pRootPopup, &nItem);

				if (!pMenuHit)
				{
					Dismiss();
					return TRUE;
				}

				RemoveMessage(lpMsg->message);
				return TRUE;
			}

		case WM_LBUTTONDBLCLK:
		case WM_NCLBUTTONDBLCLK:
		{
			CPoint point;
			GetCursorPos(&point);

			int nItem = 0;
			CXTPSkinPopupMenu* pMenuHit = FindMenu(point, m_pRootPopup, &nItem);

			if (!pMenuHit)
			{
				Dismiss();
				return TRUE;
			}

			OnButtonDblClick(pMenuHit, nItem);
		}
		return TRUE;

		case WM_LBUTTONDOWN:
		case WM_NCLBUTTONDOWN:
		{
			m_nFocus = CXTPSkinPopupMenuState::focusMouse;
			CPoint point;
			GetCursorPos(&point);

			int nItem = 0;
			CXTPSkinPopupMenu* pMenuHit = FindMenu(point, m_pRootPopup, &nItem);

			if (!pMenuHit && !nItem)
			{
				Dismiss();
				return TRUE;
			}

			if (pMenuHit == m_pAlternatePopup)
			{
				SwitchToAlternateMenu();
			}

			if (pMenuHit)
			{
				OnButtonDown(pMenuHit, nItem, TRUE);
			}

			RemoveMessage(lpMsg->message);

			return TRUE;
		}
		case WM_RBUTTONUP:
		case WM_NCRBUTTONUP:
			if (!m_bRightButton)
			{
				if (m_bButtonDown)
				{
					RemoveMessage(lpMsg->message);
					return TRUE;
				}

				return TRUE;
			}

		case WM_LBUTTONUP:
		case WM_NCLBUTTONUP:
			{
				if (!m_bButtonDown)
					return TRUE;


				CPoint point;
				GetCursorPos(&point);

				int nItem = 0;
				CXTPSkinPopupMenu* pMenuHit = FindMenu(point, m_pRootPopup, &nItem);


				if (m_pRootPopup->m_bMenuBar)
				{
					if (pMenuHit == NULL)
					{
						Dismiss();
						return TRUE;
					}
				}
				else
				{
					if (pMenuHit == NULL)
					{
						if (!m_bFirstClick)
						{
							Dismiss();
							return TRUE;
						}
					}
					m_bFirstClick = FALSE;
				}

				if (pMenuHit)
				{
					OnButtonUp(pMenuHit, nItem);
				}

				m_bButtonDown = FALSE;

				return TRUE;
			}

		case WM_MOUSEMOVE:
		case WM_NCMOUSEMOVE:
			{
				CPoint point;
				GetCursorPos(&point);

				OnMouseMove(point);
				return TRUE;
			}

		case WM_TIMER:
			{
				CXTPSkinPopupMenu* pPopupMenu = FindPopup(lpMsg->hwnd);
				if (pPopupMenu)
				{
					if (lpMsg->wParam == TIMERID_MENUSHOW && pPopupMenu->m_nShowTimer == lpMsg->wParam)
					{
						pPopupMenu->m_bToggle = FALSE;
						OpenHierarchy(pPopupMenu);
					}
					if (lpMsg->wParam == TIMERID_MENUHIDE && pPopupMenu->m_nHideTimer == lpMsg->wParam)
					{
						pPopupMenu->m_bToggle = FALSE;
						CloseHierarchy(pPopupMenu);
					}
					return TRUE;
				}

				return FALSE;
			}

		case WM_KEYDOWN:
		case WM_SYSKEYDOWN:
			{
				if (m_bButtonDown)
					return TRUE;

				m_nFocus = focusKeyboard;

				switch (lpMsg->wParam)
				{
					case VK_UP:
					case VK_DOWN:
					case VK_LEFT:
					case VK_RIGHT:
					case VK_RETURN:
					case VK_CANCEL:
					case VK_ESCAPE:
					case VK_MENU:
					case VK_F10:
					case VK_F1:
						OnKeyDown(GetActivePopup(), lpMsg->wParam);
						break;

					case VK_TAB:
						if (m_pRootPopup->m_bMenuBar && !GetNextPopup(m_pRootPopup))
						{
							Dismiss();
							return TRUE;
						}

					default:
						TranslateMessage(lpMsg);
						break;
				}
				return TRUE;
			}

		case WM_CHAR:
		case WM_SYSCHAR:
			OnChar(GetActivePopup(), lpMsg->wParam);
			return TRUE;

		case WM_SYSKEYUP:
			return TRUE;

		case WM_KEYUP:
			TranslateMessage(lpMsg);
			return TRUE;
	}

	return FALSE;
}

BOOL CXTPSkinPopupMenuState::ContinueLoop() const
{
	return (::GetCapture() == m_hWndCapture) && (m_pRootPopup != NULL) && m_bInsideMenuLoop;
}

void CXTPSkinPopupMenuState::EndMenuLoop()
{
	Dismiss();
}

void CXTPSkinPopupMenuState::RunLoop(LPARAM lParam)
{

	CPoint pt(0, 0);

	m_bInsideMenuLoop = TRUE;
	m_bDismiss = FALSE;
	BOOL bSendIdle = TRUE;

	if (!m_bMenuStarted)
	{
		if (!StartMenu(focusMouse))
		{
			EndMenuLoop();
			return;
		}

		if (m_pRootPopup->m_bMenuBar)
		{
			MSG msg;
			msg.message = WM_LBUTTONDOWN;
			msg.wParam = MK_LBUTTON;
			msg.lParam = lParam;
			msg.hwnd = m_pRootPopup->m_hWnd;
			HandleMenuMessage(&msg);
		}
	}

	// get messages until capture lost or cancelled/accepted
	while (ContinueLoop())
	{
		MSG msg;

		BOOL bPeek = PeekMessage(&msg, NULL, 0, 0, PM_NOYIELD | PM_NOREMOVE);

		if (bPeek)
		{
			BOOL bQueue = (msg.message == WM_LBUTTONDOWN ||
				msg.message == WM_RBUTTONDOWN ||
				msg.message == WM_NCLBUTTONDOWN ||
				msg.message == WM_NCRBUTTONDOWN);

			if (!bQueue)
			{
				PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
			}

			if (!HandleMenuMessage(&msg))
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}


			if (!ContinueLoop())
				break;

			if ((msg.message == WM_TIMER) || (msg.message == WM_PAINT))
				continue;

			bSendIdle = TRUE;
		}
		else
		{
			if (!ContinueLoop())
				break;

			if (bSendIdle && !m_bNoNotify && m_pRootPopup->m_hWndNotify)
			{
				SendMessage(m_pRootPopup->m_hWndNotify, WM_ENTERIDLE, MSGF_MENU, (LPARAM)GetActivePopup()->m_hWnd);

			}
			bSendIdle = FALSE;

			WaitMessage();
		}
	}

	m_bInsideMenuLoop = FALSE;
	m_hWndCapture = 0;

	EndMenuLoop();
	ReleaseCapture();

}


void CXTPSkinObjectApplicationFrame::OnContextMenu(CWnd* pWnd, CPoint pos)
{
	if ((GetSkinManager()->GetApplyOptions() & xtpSkinApplyMenus) == 0)
	{
		CXTPSkinObjectFrame::OnContextMenu(pWnd, pos);
		return;
	}

	if (pWnd && pWnd->m_hWnd != m_hWnd)
	{
		CXTPSkinObjectFrame::OnContextMenu(pWnd, pos);
		return;
	}

	LRESULT nHit = SendMessage(WM_NCHITTEST, 0, MAKELONG(pos.x, pos.y));

	if (nHit == HTCAPTION || nHit == HTSYSMENU || nHit == HTMINBUTTON  || nHit == HTMAXBUTTON || nHit == HTCLOSE)
	{
		HMENU hMenu = ::GetSystemMenu(m_hWnd, FALSE);
		if (hMenu)
		{
			int nDefault = SC_CLOSE;

			if (nHit != HTSYSMENU)
			{
				if (GetStyle() & (WS_MAXIMIZE | WS_MINIMIZE)) nDefault = SC_RESTORE; else nDefault = SC_MAXIMIZE;
			}

			::SetMenuDefaultItem(hMenu, nDefault, MF_BYCOMMAND);

			CXTPSkinObjectApplicationFrame::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON | TPM_SYSMENU, pos.x, pos.y, m_hWnd, 0);

			return;
		}
	}
	else if (nHit == HTMENU)
		return;

	CXTPSkinObjectFrame::OnContextMenu(pWnd, pos);
}

BOOL CXTPSkinObjectApplicationFrame::TrackPopupMenu(HMENU hMenu, UINT dwFlags, int x, int y, HWND hWnd, CONST RECT *prcRect)
{
	CXTPSkinPopupMenuState* pState = new CXTPSkinPopupMenuState(hWnd);
	BOOL bResult = pState->TrackPopupMenu(hMenu, dwFlags, x, y, hWnd, prcRect);
	pState->EndState();

	return bResult;
}

#define CS_DROPSHADOW       0x00020000

#ifndef SPI_GETDROPSHADOW
#define SPI_GETDROPSHADOW     0x1024
#endif

BOOL CXTPSkinPopupMenu::Create(HWND hwndParent)
{
	UINT nClassStyle = CS_SAVEBITS | CS_DBLCLKS;

	BOOL bDropShadow = FALSE;

	if (XTPSystemVersion()->IsWinXPOrGreater() && SystemParametersInfo(SPI_GETDROPSHADOW, 0, &bDropShadow, 0))
	{
		if (bDropShadow)
		{
			nClassStyle |= CS_DROPSHADOW;
		}
	}

	XTPDrawHelpers()->RegisterWndClass(0, _T("XTPSkinManagerMenu"), nClassStyle);

	UINT nWindowStyle = WS_EX_TOOLWINDOW;

	if (GetWindowLong(hwndParent, GWL_EXSTYLE) & (WS_EX_LAYOUTRTL | WS_EX_RIGHT))
	{
		nWindowStyle |= WS_EX_LAYOUTRTL;
	}

	HWND hWnd = ::CreateWindowEx(nWindowStyle, _T("XTPSkinManagerMenu"),
		NULL, WS_POPUP, 0, 0, 100, 100, hwndParent, 0, AfxGetInstanceHandle(), 0);

	if (!hWnd)
		return FALSE;

	SubclassWindow(hWnd);

	return TRUE;
}

void CXTPSkinPopupMenuState::AdjustMonitorRect(CXTPSkinPopupMenu* pPopupMenu, CPoint& pt, CSize sz, UINT wFlags, LPCRECT prcExclude)
{
	CRect rcExclude(pt.x, pt.y, pt.x, pt.y);
	CRect rcMonitor(XTPMultiMonitor()->GetScreenArea(pt));

	if (prcExclude)
	{
		rcExclude.IntersectRect(prcExclude, rcMonitor);
	}

	if (pt.x + sz.cx > rcMonitor.right)
	{
		if ((wFlags & TPM_CENTERALIGN) || (pt.x - sz.cx < rcMonitor.left) || (pt.x >= rcMonitor.right))
			pt.x = rcMonitor.right - sz.cx;
		else
			pt.x -= sz.cx;

		pPopupMenu->m_bDroppedLeft = TRUE;
	}

	if (pt.x < rcMonitor.left)
	{
		pt.x += sz.cx;
		if ((wFlags & TPM_CENTERALIGN) || (pt.x >= rcMonitor.right) || (pt.x < rcMonitor.left))
			pt.x = rcMonitor.left;
	}


	if (pt.y + sz.cy > rcMonitor.bottom)
	{
		if ((wFlags & TPM_VCENTERALIGN) || (pt.y - sz.cy < rcMonitor.top) || (pt.y >= rcMonitor.bottom))
			pt.y = rcMonitor.bottom - sz.cy;
		else
			pt.y -= sz.cy;
	 }

	if (pt.y < rcMonitor.top)
	{
		pt.y += sz.cy;
		if ((wFlags & TPM_VCENTERALIGN) || (pt.y >= rcMonitor.bottom) || (pt.y < rcMonitor.top))
			pt.y = rcMonitor.top;
	 }
}

BOOL CXTPSkinPopupMenuState::TrackPopupMenu(HMENU hMenu, UINT dwFlags, int x, int y, HWND hWnd, CONST RECT* prcRect)
{

	if (!hWnd)
		return FALSE;

	if (!hMenu)
		return FALSE;

	if (GetMenuItemCount(hMenu) == 0)
		return FALSE;

	BOOL bButtonDown = (GetKeyState(dwFlags & TPM_RIGHTBUTTON ? VK_RBUTTON : VK_LBUTTON) & 0x8000) != 0;

	CXTPSkinPopupMenu* pSubMenu = new CXTPSkinPopupMenu();
	pSubMenu->m_pState = this;

	if (!pSubMenu->Create(hWnd))
	{
		pSubMenu->InternalRelease();
		return 0;
	}

	pSubMenu->m_hMenu = hMenu;
	pSubMenu->m_hWndNotify = hWnd;
	pSubMenu->m_bSysMenu =  ((dwFlags & TPM_SYSMENU) != 0);

	m_bRightButton = ((dwFlags & TPM_RIGHTBUTTON) != 0);
	m_bNoNotify = ((dwFlags & TPM_NONOTIFY) != 0);
	m_bSynchronous = (dwFlags & TPM_RETURNCMD);

	InitMenu(pSubMenu);

	if (!StartMenu(CXTPSkinPopupMenuState::focusMouse))
	{
		pSubMenu->InternalRelease();
		return 0;
	}

	m_bFirstClick = bButtonDown;


	if (!m_bNoNotify)
	{
		SendMessage(hWnd, WM_INITMENUPOPUP, (WPARAM)hMenu, MAKELONG(0, (pSubMenu->m_bSysMenu ? 1 : 0)));
	}

	pSubMenu->m_bSendUninit = TRUE;

	CSize size = pSubMenu->RecalcLayout();

	if ((GetWindowLong(hWnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) && ((dwFlags & TPM_CENTERALIGN) == 0))
		dwFlags ^= TPM_RIGHTALIGN;

	CPoint pt(x, y);

	if (dwFlags & TPM_RIGHTALIGN)
	{
		pt.x -= size.cx;
		pSubMenu->m_bDroppedLeft = TRUE;
	}
	else if (dwFlags & TPM_CENTERALIGN)
	{
		pt.x -= size.cx / 2;
	}

	if (dwFlags & TPM_BOTTOMALIGN)
	{
		pt.y -= size.cy;
	}
	else if (dwFlags & TPM_VCENTERALIGN)
	{
		pt.y -= size.cy / 2;
	}

	AdjustMonitorRect(pSubMenu, pt, size, dwFlags, prcRect);

	PlayEventSound(xtpSoundMenuPopup);

	::SetWindowPos(pSubMenu->m_hWnd, HWND_TOPMOST, pt.x, pt.y, size.cx, size.cy, SWP_SHOWWINDOW | SWP_NOOWNERZORDER | SWP_NOACTIVATE);

	m_bButtonDown = bButtonDown;

	RunLoop(0);


	CloseHierarchy(pSubMenu);
	if (pSubMenu->m_bSendUninit && !m_bNoNotify)
	{
		SendMessage(pSubMenu->m_hWndNotify, WM_UNINITMENUPOPUP,
			(WPARAM)pSubMenu->m_hMenu, MAKELONG(0, pSubMenu->m_bSysMenu ? MF_SYSMENU: 0));
	}

	pSubMenu->DestroyWindow();
	pSubMenu->InternalRelease();

	return m_bSynchronous ? m_nLastCommand : TRUE;
}
